隨者前端需求越來越多,前端工程師在管理程式碼上的需求也越來越重,幸好 ES6 引入時 JavaScript 有引入的 ESM 的拆檔功能,以方便開發者管理程式碼,而目前大多數的 JavaScript 套件也有都使用到 ESM 的方法來做開發以及管理,算是前端工程師必學的方法之一了,而 ESM 他的全名是「ES6 Modules or JavaScript Modules」。
如果要使用 ESM 的模組化,首先必需在 <script>
標籤添加 type="module"
這樣 JavaScript 變能使用模組化的功能,而這個就模組功能,簡單來說就是使用 export
來做匯出動作 、 import
來做匯入動作,而匯出和匯入大致可分成:
由於 預設匯出 一定會搭配 預設匯入 ,具名匯出 一定會搭配 具名匯入 因此接下來就來講講這兩種狀況:
故名思義具名匯出,就會是以有名稱的方式將資料匯出,具名匯出在同一個 JS 檔案上,並沒有限制,可以同一個 JavaScript 檔案匯出多此,具名匯出則大致可分為以下幾種:
export
後使用 let
、const
宣告:export let str = 'test'
export const array = [1,2,3]
export
後使用函式陳述式:export function fn() {
console.log('具名匯出')
}
let str = 'test'
const array = [1,2,3]
function fn() {
console.log('具名匯出')
}
export const obj = {
str, array, fn
}
由於具名匯出以經帶有名稱了,因此當我們使用 具名匯入 時,匯入的名稱,會是 和具名匯出 時相同的名稱來做匯入動作,而具名匯入一般狀況會是 import { ... } form './app.js'
的方式匯入。
/* 具名匯出檔案 app.js */
let str = 'test'
const array = [1,2,3]
function fn() {
console.log('具名匯出')
}
export const obj = {
str, array, fn
}
export const number = 123
// 具名匯入檔案
<script type="module">
import { obj , number } from './app.js'
console.log(obj, number) // obj: { str: "test", array:[1,2,3] , fn: fn() } , 123
</script>
而具名匯入後其實可以更改名稱的,會使用 as
來將具名匯入的檔案更改名稱:
<script type="module">
import { obj , number as num } from './app.js' // 將 number 改為 num
console.log(obj, num ) // obj: { str: "test", array:[1,2,3] , fn: fn() } , 123
</script>
同時具名匯入也可以一口氣匯入所有資料,會使用 *
字號時,搭配 as
將匯入的資料,賦予到一個新的變數叫做 app
上,不過實做中這種一口氣匯入寫法通常較少用到:
<script type="module">
import * as app from './app.js'
console.log(app.obj, app.number ) // obj: { str: "test", array:[1,2,3] , fn: fn() } , 123
</script>
當匯出部分使用 export default
就可以知道這組是使用 預設匯出 與 預設匯入,預設匯出同樣可以匯出任何資料,字串、陣列、函式,最常見的就會是匯出一個物件,但是無法使用 變數/常數 的形式來匯出,而每個一個 JS 檔,只能使用一次預設匯出。
/* app.js */
export default {
str : 'test',
array : [1,2,3],
fn() {
console.log('預設匯出')
}
}
由於預設匯出時,並沒有使用任何名稱,因此匯入時並需使用一個名稱來接收資料
import app from './app.js'
console.log(app.str) // test
console.log(app.array) // [1,2,3]
app.fn() // 預設匯出
匯出時可同時使用預設匯出、具名匯出,而匯入部分要同時使用兩種匯入方法也是 OK 的,不過要使用這種方法,使用上會有個固定的格式。
需要同時使用兩種引入方式時,import
會先寫入預設匯入部分,設定好後,自定義名稱後方會用上逗號將 預設匯入 、具名匯入的名稱分開,而逗號後方會是 * as xxx
來將具名匯入一口氣匯入進來。
/* 匯出檔案 app.js */
let str = 'test'
const array = [1,2,3]
function fn() {
console.log('具名匯出')
}
export const obj = {
str, array, fn
}
export default 123
// 匯入檔案
<script type="module">
import number , * as obj from './app.js' // number 是預設匯入, obj 則是具名匯入。
console.log(obj, number) // obj: { str: "test", array:[1,2,3] , fn: fn() } , 123
</script>
而最後也在補充一下,當我們在 <script>
標籤添加 type= module
後其實 JavaScript 會發生一些變化,如下:
<script>
標籤來做資料存取動作,比如:<script>
const name = 'Ryder';
</script>
<script>
console.log(name); // Ryder
</script>
如果在 <script>
標籤添加 type= module
後 <script>
標籤的作用域都會被獨立,是無法在取得另一個 <script>
標籤的資料,比如:
<script>
const name = 'Ryder';
</script>
<script>
console.log(name); // ReferenceError: name is not defined
</script>
在 this 章節有提到 簡易呼叫 的 this
會指向 window,但當我們在 <script>
標籤添加 type= module
後,因為嚴格模式開啟 簡易呼叫的 this
會從 window 變為 undefined
使用前:
<script>
function fn() {
console.log(this) // window
}
fn()
</script>
使用後:
<script type="module">
function fn() {
console.log(this) // undefined
}
fn()
</script>